package com.softwaredesign.springboot.service;

import com.softwaredesign.springboot.controller.dto.UserDTO;
import com.softwaredesign.springboot.controller.dto.UserRDTO;
import com.softwaredesign.springboot.entity.User;
import com.softwaredesign.springboot.entity.UserAuthority;
import com.softwaredesign.springboot.entity.UserRole;
import com.softwaredesign.springboot.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;
    public int save(User user) {
        if (user.getId() == null) {
            return userMapper.insert(user);
        } else {
            return userMapper.update(user);
        }
    }

    public UserDTO login(UserDTO userDTO) {
        List<UserDTO> userDTOs = userMapper.login(userDTO.getUsername(), userDTO.getPassword());
        if(userDTOs == null || userDTOs.size() > 1) {
            return null;
        }
        return (userDTOs.isEmpty() ? null : userDTOs.get(0));
    }

    public boolean register(UserRDTO userRDTO) {
        if(userMapper.findUserNameOfNewUser(userRDTO.getUsername()) >= 1) {
            return false;
        }
        return userMapper.insertRDTO(userRDTO);
    }

    public UserDTO findPersonalInfoByID(Integer id) {
        User foundUser = userMapper.findPersonalInfoByID(id);
        List<Integer> roleIDs = userMapper.findUserRolesByID(id);
        UserDTO foundUserDTO = new UserDTO();
        foundUserDTO.setId(foundUser.getId());
        foundUserDTO.setUsername(foundUser.getUsername());
        foundUserDTO.setPassword(foundUser.getPassword());
        foundUserDTO.setNickname(foundUser.getNickname());
        foundUserDTO.setEmail(foundUser.getEmail());
        foundUserDTO.setPhone(foundUser.getPhone());
        foundUserDTO.setAddress(foundUser.getAddress());
        Integer userRoleCode = 0;
        Integer userAuthorityCode = 0;
        for (int i = 0; i < roleIDs.size(); i++) {
            Integer newRoleCode = userMapper.findRoleCodeByID(roleIDs.get(i));
            userRoleCode |= newRoleCode;
            List<Integer> authorities = userMapper.findRoleAuthoritiesByID(roleIDs.get(i));
            for (int j = 0; j < authorities.size(); j++) {
                Integer newAuthorityCode = userMapper.findAuthorityCodeByID(authorities.get(j));
                userAuthorityCode |= newAuthorityCode;
            }
        }
        foundUserDTO.setRoleCode(userRoleCode);
        foundUserDTO.setAuthorityCode(userAuthorityCode);
        return foundUserDTO;
    }

    public boolean updateAll(UserDTO userDTO) {
        if (userDTO.getId() == null) {
            return false;
        }
        return userMapper.updateAll(userDTO);
    }

    public Map<String, Object> findAllRole() {
        Map<String, Object> res = new HashMap<>();
        List<Integer> userIDs = userMapper.findAllUserIDs();
        if (userIDs == null || userIDs.isEmpty()) {
            res.put("data", null);
            res.put("total", 0);
            return res;
        }
        List<UserRole> userRoles = new ArrayList<>();
        for (int i = 0; i < userIDs.size(); i++) {
            String curUserName = userMapper.findUserNameByID(userIDs.get(i));
            List<Integer> roleIDs = userMapper.findUserRolesByID(userIDs.get(i));
            for (int j = 0; j < roleIDs.size(); j++) {
                Integer curRoleCode = userMapper.findRoleCodeByID(roleIDs.get(j));
                String curRoleName = userMapper.findRoleNameByID(roleIDs.get(j));
                UserRole newUserRole = new UserRole(userIDs.get(i), curUserName, roleIDs.get(j), curRoleCode, curRoleName, userIDs.get(i), roleIDs.get(j));
                userRoles.add(newUserRole);
            }
        }
        if (userRoles.isEmpty()) {
            res.put("data", null);
            res.put("total", 0);
            return res;
        }
        res.put("data", userRoles);
        res.put("total", userRoles.size());
        return res;
    }

    public Map<String, Object> findRoleOf(Integer userID,
                                          String username,
                                          Integer roleID,
                                          Integer roleCode,
                                          String roleName) {
        Map<String, Object> res = new HashMap<>();
        List<Integer> userIDs = new ArrayList<>();
        if (userID == null) {
            if (username != null) {
                userIDs = userMapper.findAllUserIDsByUserName(username);
            } else {
                userIDs = userMapper.findAllUserIDs();
            }
        } else {
            if (username != null) {
                String curUserName = userMapper.findUserNameByIDAndName(userID, username);
                if (curUserName == null) {
                    res.put("data", null);
                    res.put("total", 0);
                    return res;
                } else {
                    userIDs.add(userID);
                }
            } else {
                userIDs.add(userID);
            }
        }
        List<UserRole> userRoles = new ArrayList<>();
        for (int i = 0; i < userIDs.size(); i++) {
            String curUserName = userMapper.findUserNameByID(userIDs.get(i));
            List<Integer> roleIDs = new ArrayList<>();
            if (roleID != null) {
                Integer roleCount = userMapper.userRoleCount(userIDs.get(i), roleID);
                if (roleCount == 0) {
                    continue;
                } else {
                    for (int k = 0; k < roleCount; k++) {
                        roleIDs.add(roleID);
                    }
                }
            } else {
                roleIDs = userMapper.findUserRolesByID(userIDs.get(i));
            }
            for (int j = 0; j < roleIDs.size(); j++) {
                Integer curRoleCode = 0;
                if (roleCode != null) {
                    Integer roleCodeCount = userMapper.roleCodeCount(roleIDs.get(j), roleCode);
                    if (roleCodeCount == 0) {
                        continue;
                    } else {
                        curRoleCode = roleCode;
                    }
                } else {
                    curRoleCode = userMapper.findRoleCodeByID(roleIDs.get(j));
                }
                String curRoleName = "";
                if (roleName != null) {
                    curRoleName = userMapper.findRoleNameByIDAndSubName(roleIDs.get(j), roleName);
                } else {
                    curRoleName = userMapper.findRoleNameByID(roleIDs.get(j));
                }
                UserRole newUserRole = new UserRole(userIDs.get(i), curUserName, roleIDs.get(j), curRoleCode, curRoleName, userIDs.get(i), roleIDs.get(j));
                userRoles.add(newUserRole);
            }
        }
        if (userRoles.isEmpty()) {
            res.put("data", null);
            res.put("total", 0);
            return res;
        }
        res.put("data", userRoles);
        res.put("total", userRoles.size());
        return res;
    }

    public boolean saveUserRole(UserRole userRole) {
        if (userRole.getPreRoleID() == null && userRole.getPreUserID() == null) {
            if (userMapper.ifExitUserRole(userRole) != null) {
                return false;
            } else {
                return userMapper.insertUserRole(userRole);
            }
        } else {
            return userMapper.updateUserRole(userRole);
        }
    }

    public Map<String, Object> findAllAuthority() {
        Map<String, Object> res = new HashMap<>();
        List<Integer> userIDs = userMapper.findAllUserIDs();
        if (userIDs == null || userIDs.isEmpty()) {
            res.put("data", null);
            res.put("total", 0);
            return res;
        }
        List<UserAuthority> userAuthorities = new ArrayList<>();
        for (int i = 0; i < userIDs.size(); i++) {
            String curUserName = userMapper.findUserNameByID(userIDs.get(i));
            List<Integer> roleIDs = userMapper.findUserRolesByID(userIDs.get(i));
            for (int j = 0; j < roleIDs.size(); j++) {
                List<Integer> authorityIDs = userMapper.findRoleAuthoritiesByID(roleIDs.get(j));
                for (int k = 0; k < authorityIDs.size(); k++) {
                    Integer curAuthorityCode = userMapper.findAuthorityCodeByID(authorityIDs.get(k));
                    String curAuthorityName = userMapper.findAuthorityNameByID(authorityIDs.get(k));
                    UserAuthority newUserAuthority = new UserAuthority(userIDs.get(i), curUserName, authorityIDs.get(k), curAuthorityCode, curAuthorityName);
                    userAuthorities.add(newUserAuthority);
                }
            }
        }
        if (userAuthorities.isEmpty()) {
            res.put("data", null);
            res.put("total", 0);
            return res;
        }
        res.put("data", userAuthorities);
        res.put("total", userAuthorities.size());
        return res;
    }

    public Map<String, Object> findAuthorityOf(Integer userID) {
        Map<String, Object> res = new HashMap<>();
        List<Integer> userIDs = new ArrayList<>();
        if (userID == null) {
            userIDs = userMapper.findAllUserIDs();
        } else {
            userIDs.add(userID);
        }
        List<UserAuthority> userAuthorities = new ArrayList<>();
        for (int i = 0; i < userIDs.size(); i++) {
            String curUserName = userMapper.findUserNameByID(userIDs.get(i));
            List<Integer> roleIDs = userMapper.findUserRolesByID(userIDs.get(i));
            for (int j = 0; j < roleIDs.size(); j++) {
                List<Integer> authorityIDs = userMapper.findRoleAuthoritiesByID(roleIDs.get(j));
                for (int k = 0; k < authorityIDs.size(); k++) {
                    Integer curAuthorityCode = userMapper.findAuthorityCodeByID(authorityIDs.get(k));
                    String curAuthorityName = userMapper.findAuthorityNameByID(authorityIDs.get(k));
                    UserAuthority newUserAuthority = new UserAuthority(userIDs.get(i), curUserName, authorityIDs.get(k), curAuthorityCode, curAuthorityName);
                    userAuthorities.add(newUserAuthority);
                }
            }
        }
        if (userAuthorities.isEmpty()) {
            res.put("data", null);
            res.put("total", 0);
            return res;
        }
        res.put("data", userAuthorities);
        res.put("total", userAuthorities.size());
        return res;
    }
}
